package com.googlecode.animator.view.viewport
{
	import com.googlecode.animator.data.cameras.CameraVO;
	
	import flash.events.TimerEvent;
	import flash.geom.Rectangle;
	import flash.utils.Timer;
	
	import mx.core.UIComponent;
	
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.render.BasicRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;
	import org.papervision3d.view.layer.ViewportLayer;
	

	/**
	 * The viewport component enables a view into the 3D world, as seen through a camera. 
	 *  
	 * @author USER
	 * 
	 */
	public class Viewport extends UIComponent
	{
		private var _vWidth:int;		
		private var _vHeight:int;					
		
		protected var _renderer:BasicRenderEngine;
		protected var _camera:Camera3D;	
		protected var _zoomScale:int;	
		protected var _viewport:Viewport3D;
		protected var _scene:Scene3D;
		
		
		/**
		 * Constructor. 
		 * 
		 */
		public function Viewport()
		{
			super();

		}
				
		/**
		 * Sets up the viewport. 
		 * 
		 */
		public function setupViewport():void
		{
			// create viewport from papervision3d classes
			_viewport = new Viewport3D(vWidth, vHeight, false, false);
			_viewport.interactive = true;
			//_viewport.graphics.beginFill(0xff0000, 0);
			//_viewport.graphics.drawRect(0, 0, vWidth, vHeight);			

			addChild(_viewport);
			
			
			// viewport has a permanent camera. It can be set-up as needed.
			_camera = new Camera3D();
			
		}
		
		/**
		 * Adds a 3D object to the scene. 
		 * 
		 */
		public function addViewportObject3D(object3D:DisplayObject3D):void
		{
			_scene.addChild(object3D);
		}
		
		
		//////////////////////////////////////////////////////////////////////
		//
		// Camera functions: each viewport requires a 3D camera.
		//
		//////////////////////////////////////////////////////////////////////
		
		/**
		 * Updates camera position and zoom properties. 
		 * @param VO
		 * 
		 */
		public function updateViewportCamera(camera:CameraVO):void
		{			
			_camera.x = camera.x;
			_camera.y = camera.y;
			_camera.z = camera.z;
			_camera.zoom = camera.zoom;
			_camera.roll(camera.roll);
			_camera.yUP = camera.yUp == "false" ? false : true;
			
			var target:DisplayObject3D = new DisplayObject3D();
			target.x = camera.target.x;
			target.y = camera.target.y;
			target.z = camera.target.z;
			
			_camera.lookAt(target);			
		}
		
		//////////////////////////////////////////////////////////////////////
		//
		// Utility functions
		//
		//////////////////////////////////////////////////////////////////////
		
		/**
		 * Makes the named object3D invisible in this viewport. 
		 * @param name
		 * 
		 */
		public function makeViewportObject3DInvisible(name:String):void
		{
			var child:DisplayObject3D = _scene.getChildByName(name);
			var vpl:ViewportLayer = _viewport.getChildLayer(child);
			vpl.mouseEnabled = false;
			vpl.visible = false;
		}
		
		/**
		 * Makes the named object3D visible in this viewport. 
		 * @param name
		 * 
		 */
		public function makeViewportObject3DVisible(name:String):void
		{
			 var child:DisplayObject3D = _scene.getChildByName(name);
			var vpl:ViewportLayer = _viewport.getChildLayer(child);
			vpl.mouseEnabled = true;
			vpl.visible = true; 
		}
		
		/**
		 * Renders this viewport. 
		 * 
		 */
		public function render():void
		{
			if(_camera == null)
			{
				return;
			}

			_renderer.renderScene(_scene, _camera, _viewport);
		}
		
		/**
		 * Centres viewport. 
		 * 
		 */
		public function centreViewport():void
		{
			var offsetX:Number = (vWidth - this.parent.width) / 2;
			var offsetY:Number = (vHeight - this.parent.height) / 2;
			
			var viewArea:Rectangle = new Rectangle(offsetX, offsetY, this.parent.width, this.parent.height);
			_viewport.scrollRect = viewArea;
		}
		
		/**
		 * Cleans up viewport before it is removed. 
		 * 
		 */
		public function destroy():void
		{			
			_viewport = null;
			_camera = null;
			_renderer = null;
			
			
		}
		
		
		//////////////////////////////////////////////////////////////////////
		//
		// Overriden Flex functions
		//
		//////////////////////////////////////////////////////////////////////
		
		/**
		 * Called by Flex in response to the display list being updated and the stage being redrawn.
		 *  
		 * @param unscaledWidth
		 * @param unscaledHeight
		 * 
		 */
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);

			if(_viewport != null)
			{
				centreViewport();
			}
						
		}
		
		//////////////////////////////////////////////////////////////////////
		//
		// Public getters and setters
		//
		//////////////////////////////////////////////////////////////////////
		
		/**
		 * Gets a reference to the viewport. 
		 * @return 
		 * 
		 */
		public function get viewport():Viewport3D
		{
			return _viewport;
		}
		
		/**
		 * Sets and gets the viewport width. 
		 * @param value
		 * 
		 */
		public function set vWidth(value:int):void
		{
			_vWidth = value;
		}
		
		public function get vWidth():int
		{
			return _vWidth;
		}
		
		/**
		 * Sets and gets the viewport height.
		 * @param value
		 * 
		 */
		public function set vHeight(value:int):void
		{
			_vHeight = value;
		}
		public function get vHeight():int
		{
			return _vHeight;
		}

		/**
		 * Set a reference to the 3D scene so that it can be used locally. 
		 * @param s
		 * 
		 */
		public function set scene(s:Scene3D):void
		{
			_scene = s;
			
		}
		
		/**
		 * Set a reference to the renderer so that it can be used locally.
		 * @param r
		 * 
		 */
		public function set renderer(r:BasicRenderEngine):void
		{
			_renderer = r;
		}
		
		/**
		 * Gets and sets the zoom for this viewport. 
		 * @param z
		 * 
		 */
		public function set zoom(z:int):void
		{
			
			_camera.zoom = z;
		}
		
		public function get zoom():int
		{
			return _camera.zoom;
		} 
	}
}